package org.opens.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 功能:
 *
 * @author zym
 * @Date 2021/11/19 9:46
 */
public class ZipUtil {

    /**
     * 默认编码，使用平台相关编码
     */
    private static final Charset DEFAULT_CHARSET = Charset.defaultCharset();

    private static int BUFFER = 2048;

    /**
     * 功能: 将sourceFilePath这个路径或者文件压缩到zipFilePath路径下
     * @param sourceFilePath    压缩源
     * @param zipFilePath       压缩目标位置
     */
    public static void zip(String sourceFilePath, String zipFilePath) {
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFilePath))) {
            doZip("", sourceFilePath, zipOutputStream);
            zipOutputStream.finish();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能: 真实的压缩方法
     * @param parentFilePath    父级节点名称
     * @param filePath          压缩文件输出路径
     * @param zipOutputStream   压缩文件输出流
     */
    private static void doZip(String parentFilePath, String filePath, ZipOutputStream zipOutputStream) {
        File sourceFile = new File(filePath);
        if (!sourceFile.exists()) {
            return;
        }
        String zipEntryName = parentFilePath + "/" + sourceFile.getName();
        if (StrUtil.isEmpty(parentFilePath)) {
            zipEntryName = sourceFile.getName();
        }

        if (sourceFile.isDirectory()) {
            File[] childFiles = sourceFile.listFiles();
            if (childFiles == null) {
                return;
            }
            for (File childFile : childFiles) {
                doZip(zipEntryName, childFile.getAbsolutePath(), zipOutputStream);
            }
        } else {
            int len = -1;
            byte[] buffer = new byte[1024];
            try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(sourceFile))) {
                zipOutputStream.putNextEntry(new ZipEntry(zipEntryName));
                while((len = bufferedInputStream.read(buffer)) != -1) {
                    zipOutputStream.write(buffer, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 功能: 将压缩文件zipFilePath解压到指定路径下
     * @param zipFilePath   压缩文件路径
     * @param destFilePath  解压路径
     */
    public static void unzip(String zipFilePath, String destFilePath) {
        File file = new File(zipFilePath);
        if (!file.exists()) {
            throw new IllegalArgumentException("源文件" + zipFilePath + "不存在!");
        }

        try(
                ZipFile zipFile = new ZipFile(file, DEFAULT_CHARSET);
                FileInputStream fileInputStream = new FileInputStream(file);
                ZipInputStream zipInputStream = new ZipInputStream(fileInputStream);
        ) {
            ZipEntry zipEntry = null;
            // 兼容linux下的文件路径符号与windows下的不同
            String[] zipFileNameSplitRes = zipFile.getName().split("/|\\\\");
            String zipFileName = zipFileNameSplitRes[zipFileNameSplitRes.length - 1];

            // 先创建同名目录
            File unzipDir = new File(destFilePath, zipFileName.split("\\.")[0]);
            if (!unzipDir.exists()) {
                unzipDir.mkdirs();
            }

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                // 增加zipFileName.split("\\.")[0]是为了解压后生成压缩文件路径下
                File entryFile = new File(unzipDir.getAbsolutePath(), zipEntry.getName());
                // 如果当前节点是目录, 则只创建目录
                if (zipEntry.isDirectory()) {
                    entryFile.mkdir();
                } else {
                    // 如果当前节点是文件, 则进行复制内容
                    if (!entryFile.getParentFile().exists()) {
                        entryFile.getParentFile().mkdirs();
                    }
                    entryFile.createNewFile();
                    try (
                            InputStream inputStream = zipFile.getInputStream(zipEntry);
                            OutputStream outputStream = new FileOutputStream(entryFile);
                    ) {
                        int len = -1;
                        byte[] buffer = new byte[1024];
                        while ((len = inputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, len);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解压到zip文件所在路径下, 解压目录名使用zip文件名
     * @param zipFilePath 待解压zip文件路径
     */
    public static void unzip(String zipFilePath) {
        File zipFile = new File(zipFilePath);
        if (!zipFile.exists()) {
            throw new RuntimeException("解压源文件不存在!");
        }
        unzip(zipFilePath, zipFile.getParent());
    }

    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    public static boolean isWindows() {
        return System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
    }

    /**
     * 将指定的文件压缩为一个zip包
     * @param files 源文件
     * @param zipDescPath 压缩目标路径
     */
    public static void zipFilesToZip(List<File> files, String zipDescPath) {
        if (StrUtil.isEmpty(zipDescPath)) {
            throw new IllegalArgumentException("生成路径不能为空!");
        }

        if (CollectionUtil.isEmpty(files)) {
            throw new IllegalArgumentException("文件源不能为空!");
        }

        if (!zipDescPath.endsWith(".zip")) {
            throw new IllegalArgumentException("生成路径必须是.zip结尾!");
        }

        FileOutputStream fileOutputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(zipDescPath);
            zipOutputStream = new ZipOutputStream(fileOutputStream);

            for (int i = 0; i < files.size(); i++) {
                FileInputStream fileInputStream = null;
                File file = files.get(i);
                ZipEntry zipEntry = new ZipEntry(file.getName());
                zipEntry.setTime(file.lastModified());
                try {
                    zipOutputStream.putNextEntry(zipEntry);

                    fileInputStream = new FileInputStream(file);
                    IoUtil.copy(fileInputStream, zipOutputStream);

                    zipOutputStream.closeEntry();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    IoUtil.close(fileInputStream);
                }
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            IoUtil.close(zipOutputStream);
            IoUtil.close(fileOutputStream);
        }
    }



    public static String unZip2(String filePath, String zipDir) {
        String name = "";
        try {
            BufferedOutputStream dest = null;
            BufferedInputStream is = null;
            ZipEntry entry;
            ZipFile zipfile = new ZipFile(filePath);

            Enumeration dir = zipfile.entries();
            while (dir.hasMoreElements()) {
                entry = (ZipEntry) dir.nextElement();

                if (entry.isDirectory()) {
                    name = entry.getName();
                    name = name.substring(0, name.length() - 1);
                    File fileObject = new File(zipDir + name);
                    fileObject.mkdir();
                }
            }

            Enumeration e = zipfile.entries();
            while (e.hasMoreElements()) {
                entry = (ZipEntry) e.nextElement();
                if (entry.isDirectory()) {
                    continue;
                } else {
                    is = new BufferedInputStream(zipfile.getInputStream(entry));
                    int count;
                    byte[] dataByte = new byte[BUFFER];
                    FileOutputStream fos = new FileOutputStream(zipDir + entry.getName());
                    dest = new BufferedOutputStream(fos, BUFFER);
                    while ((count = is.read(dataByte, 0, BUFFER)) != -1) {
                        dest.write(dataByte, 0, count);
                    }
                    dest.flush();
                    dest.close();
                    is.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return name;
    }

    public static void main(String[] args) {
        List<File> files = Arrays.asList(
                new File("C:\\Users\\zhangyuming\\Desktop\\jarTemp\\a\\001\\a.txt"),
                new File("C:\\Users\\zhangyuming\\Desktop\\jarTemp\\a\\001\\b.txt"),
                new File("C:\\Users\\zhangyuming\\Desktop\\jarTemp\\a\\001\\c.txt"),
                new File("C:\\Users\\zhangyuming\\Desktop\\jarTemp\\a\\001\\d.txt")
        );
        zipFilesToZip(files, "C:\\Users\\zhangyuming\\Desktop\\jarTemp\\a\\c111.zip");
    }

}
